library(quantmod)
## Loading required package: xts
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
## Loading required package: TTR
## Version 0.4-0 included new data defaults. See ?getSymbols.
symbls <- c("AAPL", "MSFT", "^GSPC")
getSymbols(symbls, auto.assign = T)
## 'getSymbols' currently uses auto.assign=TRUE by default, but will
## use auto.assign=FALSE in 0.5-0. You will still be able to use
## 'loadSymbols' to automatically load data. getOption("getSymbols.env")
## and getOption("getSymbols.auto.assign") will still be checked for
## alternate defaults.
##
## This message is shown once per session and may be disabled by setting
## options("getSymbols.warning4.0"=FALSE). See ?getSymbols for details.
##
## WARNING: There have been significant changes to Yahoo Finance data.
## Please see the Warning section of '?getSymbols.yahoo' for details.
##
## This message is shown once per session and may be disabled by setting
## options("getSymbols.yahoo.warning"=FALSE).
## [1] "AAPL" "MSFT" "GSPC"
Ratio expressing the value of the share price of Apple in terms of the share price of Microsoft
Note that where the value of the ratio is larger than one, the Apple outperforms Microsoft and vice versa.
aapl_msft = AAPL$AAPL.Adjusted/MSFT$MSFT.Adjusted
plot.zoo(aapl_msft)
abline(h=1)
N = 2
weights <- rep(1/N,N)
weights
## [1] 0.5 0.5
barplot(weights, ylim = 0:1)
# Define the vector values
values <- c(4000, 6000)
# Define the vector weights
weights <- values/sum(values)
# Print the resulting weights
## Should sum up to unity
weights
## [1] 0.4 0.6
barplot(weights, ylim = 0:1)
\[ Portfolio Returns = w_1R_1 + w_2R_2 + ... + w_nR_n \]
# Vector of initial value of the assets
in_values <- c(1000,5000,2000)
# Vector of final values of the assets
fin_values <- c(1100, 4500, 3000)
# Weights as the proportion of total value invested in each assets
weights <- in_values/sum(in_values)
weights
## [1] 0.125 0.625 0.250
# Vector of simple returns of the assets
returns <- (fin_values - in_values)/in_values
returns
## [1] 0.1 -0.1 0.5
# Compute portfolio return using the portfolio return formula
preturns <- sum(weights*returns)
preturns
## [1] 0.075
The simple return \(R\) expresses the percentage change in value of an investment. The corresponding so-called “gross” return is defined as the future value of 1 USD invested in the asset for one period, and is thus equal to \(1+R\)
The gross return over two periods is obtained similarly. Let \(R_1\) be the return in the first period and \(R_2\) the return in the second period. Then the end-value of a 1 USD investment is \((1+R_1)∗(1+R_2)\)
The corresponding simple return over those two periods is: \((1+R_1)∗(1+R_2)−1\)
Suppose that you have an investment horizon of two periods. In the first period you make a 10% return. But in the second period you take a loss of 5%.
(1+.1)*(1-.05)*1000
## [1] 1045
It is important to be aware of the fact that a positive and negative return of the same relative magnitude do not compensate each other in terms of terminal wealth. Mathematically, this can be seen from the identity \((1+x)∗(1−x)=1−x^2\), which is less than one. A 50% loss is thus not compensated by a 50% gain. After a loss of 50%, what is the return needed to be at par again?
(1-.5)*(1+.5)
## [1] 0.75
1-.5^2
## [1] 0.75
(1-.5)*(1+1)
## [1] 1
library(PerformanceAnalytics)
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
prices <- merge(AAPL$AAPL.Adjusted,
MSFT$MSFT.Adjusted)
colnames(prices) <- c("AAPL", "MSFT")
returns <- Return.calculate(prices)
returns <- returns[(-1),]
head(returns, n=2)
## AAPL MSFT
## 2007-01-04 0.022195701 -0.001674669
## 2007-01-05 -0.007121306 -0.005702811
Your portfolio approach will be to invest half of your budget in Apple stock, and the other half of your budget in Microsoft stock. Over time, the portfolio weights will change. You will have two choices as an investor. The first choice is to be passive and not trade any further. This is called a buy and hold strategy. The second choice is to buy and trade at the close of each day that results in a rebalance of the portfolio such that your portfolio is equally invested in shares of Microsoft and Apple. This is a rebalanced portfolio.
# Create the weights
eq_weights <- c(0.5, 0.5)
# Create a portfolio using buy and hold
pf_bh <- Return.portfolio(R = returns, weights = eq_weights)
# Create a portfolio rebalancing monthly
pf_rebal <- Return.portfolio(R = returns, weights = eq_weights, rebalance_on="months")
# Plot the time-series
# par(mfrow = c(2, 1), mar=c(2, 4, 2, 2))
plot.zoo(pf_bh)
plot.zoo(pf_rebal)
# Create the weights
eq_weights <- c(.5,.5)
# Create a portfolio using buy and hold
pf_bh <- Return.portfolio(returns, weights = eq_weights, verbose=T )
# Create a portfolio that rebalances monthly
pf_rebal <- Return.portfolio(returns, weights = eq_weights, rebalance_on = "months", verbose=T )
# Create eop_weight_bh
eop_weight_bh <- pf_bh$EOP.Weight
# Create eop_weight_rebal
eop_weight_rebal <- pf_rebal$EOP.Weight
# Plot end of period weights
# par(mfrow = c(2, 1), mar=c(2, 4, 2, 2))
plot.zoo(eop_weight_bh$AAPL)
plot.zoo(eop_weight_rebal$AAPL)
plot.zoo(eop_weight_bh$MSFT)
plot.zoo(eop_weight_rebal$MSFT)
\[ \hat{\mu} = \frac{R_1+R_2+...+R_T}{T} \] - De-meaned return
\[ R_i - \hat{\mu} \] - Portfolio variance
\[ \hat{\sigma}^2 = \frac{(R_1 - \hat{\mu})^2+(R_2 - \hat{\mu})^2+...+(R_T - \hat{\mu})^2}{T-1} \] - Portfolio volatility (standard deviation)
\[ \hat{\sigma} = \sqrt{\hat{\sigma}^2} \] - Geometric Mean Return
\[ GeometricMean = \bigg[ (1+R_1)*(1+R_1) *... * (1+R_T) \bigg]^{\frac{1}{T}} -1 \] – Example: +50% and -50% return
\[ GeometricMean = \bigg[ (1+0.5)*(1-0.5) \bigg]^{\frac{1}{2}} -1 \\ = 0.75^{\frac{1}{2}} - 1 \\ = -13.4\% \]
sp500 <- GSPC$GSPC.Adjusted
colnames(sp500) <- c("GSPC")
sp500_monthly <- to.monthly(sp500, OHLC=F)
head(sp500_monthly, n=2)
## GSPC
## Jan 2007 1438.24
## Feb 2007 1406.82
sp500_returns <- Return.calculate(sp500_monthly)
sp500_returns <- sp500_returns[-1]
# Time series plot
plot.zoo(sp500_returns)
# Produce the year x month table
table.CalendarReturns(sp500_returns)
# Compute the mean monthly returns
mean(sp500_returns)
## [1] 0.005358624
# Compute the geometric mean of monthly returns
mean.geometric(sp500_returns)
## GSPC
## Geometric Mean 0.004442769
# Compute the standard deviation
sd(sp500_returns)
## [1] 0.0425496
random <- runif(length(sp500_returns), min =0, max = 0.5)*0.00001 + 0.0001
rf <- xts(random, order.by = index(sp500_returns))
# Compute the annualized risk free rate
annualized_rf <- (1 + rf)^12 - 1
# Plot the annualized risk free rate
plot.zoo(annualized_rf)
# Compute the series of excess portfolio returns
sp500_excess <- sp500_returns - rf
# Compare the mean
mean(sp500_excess)
## [1] 0.005256256
mean(sp500_returns)
## [1] 0.005358624
# Compute the Sharpe ratio
sp500_sharpe <- mean(sp500_excess) / sd(sp500_returns)
sp500_sharpe
## [1] 0.1235324
# Compute the annualized mean
ar <- Return.annualized.excess(sp500_returns, Rb=0)
ar
## GSPC
## Annualized Return 0.05463544
# Compute the annualized standard deviation
astd <- StdDev.annualized(sp500_returns)
astd
## GSPC
## Annualized Standard Deviation 0.1473961
# Compute the annualized Sharpe ratio: ann_sharpe
ann_sharpe <- ar/astd
ann_sharpe
## GSPC
## Annualized Return 0.3706708
# Compute all of the above at once using table.AnnualizedReturns()
table.AnnualizedReturns(sp500_returns)
# Calculate the mean, volatility, and sharpe ratio of sp500_returns
returns_ann <- Return.annualized.excess(sp500_returns, 0)
sd_ann <- StdDev.annualized(sp500_returns)
sharpe_ann <- SharpeRatio.annualized(sp500_returns, rf)
# Plotting the 12-month rolling annualized mean
chart.RollingPerformance(R = sp500_returns, width = 12, FUN = "Return.annualized.excess", Rb=0)
abline(h = returns_ann)
# Plotting the 12-month rolling annualized standard deviation
chart.RollingPerformance(R = sp500_returns, width = 12, FUN = "StdDev.annualized")
abline(h = sd_ann)
# Plotting the 12-month rolling annualized Sharpe ratio
chart.RollingPerformance(R = sp500_returns, Rf=rf, width = 12, FUN = "SharpeRatio.annualized")
abline(h = sharpe_ann)
# Fill in window for 2008
sp500_2008 <- window(sp500_returns, start = "2008-01-01", end = "2008-12-31")
# Create window for 2014
sp500_2014 <- window(sp500_returns, start = "2014-01-01", end = "2014-12-31")
# Plotting settings
# par(mfrow = c(1, 2) , mar=c(3, 2, 2, 2))
names(sp500_2008) <- "sp500_2008"
names(sp500_2014) <- "sp500_2014"
# Plot histogram of 2008
chart.Histogram(sp500_2008, methods = c("add.density", "add.normal"))
# Plot histogram of 2014
chart.Histogram(sp500_2014, methods = c("add.density", "add.normal"))
\[ SemiDev = \sqrt{\frac{(Z_1-\mu)^2+(Z_2-\mu)^2+...+(Z_n-\mu)^2}{n}} \]
# Calculate the SemiDeviation
SemiDeviation(sp500_returns)
## GSPC
## Semi-Deviation 0.03260378
# Calculate the value at risk
VaR(sp500_returns, 0.025)
## GSPC
## VaR -0.09413028
VaR(sp500_returns, 0.05)
## GSPC
## VaR -0.07135515
# Calculate the expected shortfall
ES(sp500_returns, 0.025)
## GSPC
## ES -0.1448913
ES(sp500_returns, 0.05)
## GSPC
## ES -0.1088014
skewness(sp500_returns)
## [1] -0.7369794
kurtosis(sp500_returns)
## [1] 1.7072
The volatility, semi-deviation, value-at-risk, and expected shortfall are all measures that describe risk over 1 period. These metrics do not do a great job at describing the worst case risk of buying at a peak, and selling at a trough. This sort of risk can be quantified by analyzing the portfolio’s drawdowns, or peak-to-trough decline in cumulative returns.
# Table of drawdowns
# table.Drawdowns(sp500_returns, drop)
# Plot of drawdowns
chart.Drawdown(sp500_returns)
Return –> Random Variable –> Expectation
\[ PortfolioReturn = w_1R_1+w_2R_2+...+w_nR_n \\ \mathbf{E}[P] = w_1\mathbf{E}[R_1] + w_2\mathbf{E}[R_2] + ... + w_n\mathbf{E}[R_n] \] #### Variance of Portfolio Return \[ var(P) = \mathbf{E}\Big[\big(P - \mathbf{E}[P]^2\big)\Big] = w_1^2* var(R_1) \\ + w_2 * var(R_2) \\ + 2 * w_1 * w_2 * cov(R_1,R_2) \] #### Covariance between \(R_!\) and \(R_2\) \[ cov(R_1,R_2) = \mathbf{E}\Big[\big(R_1 - \mathbf{E}[R_1]\big)\big(R_2 - \mathbf{E}[R_2]\big)\Big] \\ = StdDev(R_1) * StdDev(R_2) * corr(R_1,R_2) \] ## Drivers of Performance
returns_6040 = 0.6 * returns$AAPL + 0.4 * returns$MSFT
all.equal(mean(returns_6040), 0.6 * mean(returns$AAPL) + 0.4 * mean(returns$MSFT))
## [1] TRUE
Investors can optimize the choice of weight to obtain the highest risk-adjusted return, as measured by the portfolio Sharpe ratio.
In the special case of investing the total portfolio value in only two assets, there is only one weight to determine, because the weight on the second asset equals one minus the weight of the first asset.
# Create a grid
grid <- seq(0, 1, 0.01)
# Initialize an empty vector for sharpe ratios
vsharpe <- rep(NA, times = length(grid))
# Create a for loop to calculate sharpe ratios
for(i in 1:length(grid)) {
weight <- grid[i]
preturns <- weight * returns$AAPL + (1 - weight) * returns$MSFT
vsharpe[i] <- SharpeRatio.annualized(preturns)
}
# Plot weights and sharpe ratio
plot(grid, vsharpe, xlab = "Weights", ylab = "Ann. Sharpe ratio")
abline(v = grid[vsharpe == max(vsharpe)], lty = 3)
### Driver 3: The correlation between the asset returns
The third driver of portfolio performance is the correlation between the asset returns. Generally speaking, the correlation tells you how two asset returns tend to move together.
The correlation of assets has important consequences in overall portfolio performance. This correlation is important because it can reduce volatility through diversification, or reducing overall correlation. In fact, the lower the correlation, the more succesful the portfolio tends to be in regards to partially offsetting large losses in one asset with only a minor loss, or even a gain, in another asset.
In the extreme case of two identical asset returns, the correlation will be 1, and there is no diversification potential. In the other extreme case where, if one asset return is above average, and the other is almost always below average, the correlation is negative. The correlation is 0 when the asset returns are linearly independent of each other. Note that interdependency can still exist on a non-linear level even when the correlation is 0.
Now you will learn how to compute the correlation between equity returns and bond returns. Just like volatilities, these correlations are dynamic. Therefore you need to distinguish between a static analysis that calculates correlations over a complete sample, and a dynamic analysis that calculates correlations over a rolling sample. This is a similar analysis as you did for the time-varying performance evaluation in terms of mean return and volatility.
In this exercise you will learn 3 new functions from the PerformanceAnalytics package: chart.Scatter(), chart.Correlation(), and chart.RollingCorrelation().
# Create a scatter plot
chart.Scatter(returns$MSFT, returns$AAPL, type = "p")
# Find the correlation
cor(returns$AAPL, returns$MSFT)
## MSFT
## AAPL 0.4713825
# Merge returns_equities and returns_bonds
returns <- merge(returns$AAPL, returns$MSFT)
# Find and visualize the correlation using chart.Correlation
chart.Correlation(returns)
# Visualize the rolling estimates using chart.RollingCorrelation
chart.RollingCorrelation(returns$AAPL, returns$MSFT)
\(\mathbf{w}\): the \(N \times 1\) column-matrix of portfolio weights \[ \mathbf{w} = \begin{bmatrix} w_1 \\ w_2 \\ \vdots \\ w_N \end{bmatrix} \] \(\mathbf{R}\): the \(N \times 1\) column-matrix of asset returns \[ \mathbf{R} = \begin{bmatrix} R_1 \\ R_2 \\ \vdots \\ R_N \end{bmatrix} \] \(\mathbf{\mu}\): the \(N \times 1\) column-matrix of expected returns \[ \mathbf{\mu} = \begin{bmatrix} \mu_1 \\ \mu_2 \\ \vdots \\ \mu_N \end{bmatrix} \]
\(\mathbf{\Sigma}\): the \(N \times N\) cavariance matrix of the \(N\) asset returns
\[ \mathbf{\Sigma} = \begin{pmatrix} \sigma_{11}^2 & \sigma_{12} & \cdots & \sigma_{1N} \\ \sigma_{21} & \sigma_{22}^2 & \cdots & \sigma_{2N} \\ \vdots & \vdots & \ddots & \vdots \\ \sigma_{N1} & \sigma_{N2} & \cdots & \sigma_{NN}^2 \end{pmatrix} \] ### General Case - Portfolio Return \[ \mathbf{w}'\mathbf{R} \]
# Create a vector of returns
means <- apply(returns, 2, "mean")
# Create a vector of standard deviation
sds <- apply(returns, 2, "sd")
# Create a scatter plot
plot(sds, means)
text(sds, means, labels = colnames(returns), cex = 0.7)
abline(h = 0, lty = 3)
# Create a matrix with variances on the diagonal
diag_cov <- diag(sds^2)
# Create a covariance matrix of returns
cov_matrix <- cov(returns)
# Create a correlation matrix of returns
cor_matrix <- cor(returns)
# Verify covariances equal the product of standard deviations and correlation
current <- cor_matrix[1,2] * sds[1] * sds[2]
names(current) <- NULL
all.equal(cov_matrix[1,2], current[1])
## [1] TRUE
# Create a weight matrix w
w <- as.matrix(c(.5,.5))
# Create a matrix of returns
mu <- as.matrix(means)
# Calculate portfolio mean monthly returns
t(w) %*% mu
## [,1]
## [1,] 0.0009513917
# Calculate portfolio volatility
sqrt(t(w) %*% cov_matrix %*% w)
## [,1]
## [1,] 0.01604969
How much of the portfolio risk is caused by individual positions?
Capital Allocation Budget vs Portfolio Volatility Risk
\[ Portfolio Volatility = \sum_{i=1}^N RC_i \\ \text{where: } RC_i = \frac{w_i(\Sigma w)_i}{\sqrt{w'\Sigma w}} \] - Percentage Risk Contribution \[ \% RC_i = \frac{RC_i}{PortfolioVolatility} \\ \text{where: } \sum_{i=1}^N \%RC_i =1 \] Relatively more risky assets: \(\%RC_i \gt w_i\) Relatively less risky assets: \(\%RC_i \lt w_i\)
# Create portfolio weights
weights <- c(.5,.5)
# Create volatility budget
vol_budget <- StdDev(returns, portfolio_method = "component", weights = weights)
# Make a table of weights and risk contribution
weights_percrisk <- cbind(weights, vol_budget$pct_contrib_StdDev)
colnames(weights_percrisk) <- c("weights", "perc vol contrib")
# Print the table
weights_percrisk
## weights perc vol contrib
## AAPL 0.5 0.5498808
## MSFT 0.5 0.4501192
No other portfolio exists with a higher expected return at the same or lowe level of volatility (no portfolio on the upper left when y=meanPortfolioReturn and x=volatility)
# Create a vector of row means
ew_preturns <- rowMeans(returns)
# Cast the numeric vector back to an xts object
ew_preturns <- xts(ew_preturns, order.by = time(returns))
# Plot ew_preturns
plot.zoo(ew_preturns)
# Load tseries
library(tseries)
# Create an optimized portfolio of returns
opt <- portfolio.optim(returns)
# Create pf_weights
pf_weights <- opt$pw
# Assign asset names
names(pf_weights) <- colnames(returns)
# Select optimum weights opt_weights
opt_weights <- pf_weights[pf_weights>= 0.01]
opt_weights
## AAPL MSFT
## 0.5 0.5
# Barplot of opt_weights
barplot(opt_weights)
# Print expected portfolio return and volatility
opt$pm
## [1] 0.0009513917
opt$ps
## [1] 0.01604969
# Create portfolio with target return of average returns
pf_mean <- portfolio.optim(returns, pm = mean(returns))
# Create portfolio with target return 10% greater than average returns
pf_10plus <- portfolio.optim(returns, pm = 1.1 * mean(returns))
# Print the standard deviations of both portfolios
pf_mean$ps
## [1] 0.01604969
pf_10plus$ps
## [1] 0.01676841
# Calculate the proportion increase in standard deviation
(pf_10plus$ps - pf_mean$ps) / (pf_mean$ps)
## [1] 0.04478078
Investors are often constrained by the maximum values allowed for the portfolio weights. These constraints can actually be an advantage. The advantage of a maximum weight constraint is that the subsequent portfolio will be less concentrated in certain assets. There is a disadvantage to this though. The disadvantage is that the same target return may no longer be possible or will be obtained at the expense of a higher volatility.
# Create vectors of maximum weights
max_weights1 <- rep(1, ncol(returns))
max_weights2 <- rep(0.8, ncol(returns))
max_weights3 <- rep(0.6, ncol(returns))
# Create an optimum portfolio with max weights of 100%
opt1 <- portfolio.optim(returns, reshigh = max_weights1)
# Create an optimum portfolio with max weights of 10%
opt2 <- portfolio.optim(returns, reshigh = max_weights2)
# Create an optimum portfolio with max weights of 5%
opt3 <- portfolio.optim(returns, reshigh = max_weights3)
# Calculate how many assets have a weight that is greater than 1% for each portfolio
sum(opt1$pw > .01)
## [1] 2
sum(opt2$pw > .01)
## [1] 2
sum(opt3$pw > .01)
## [1] 2
# Print portfolio volatilites
opt1$ps
## [1] 0.01604969
opt2$ps
## [1] 0.01604969
opt3$ps
## [1] 0.01604969
# Calculate each stocks mean returns
stockmu <- colMeans(returns)
# Create a grid of target values
grid <- seq(0.001, max(stockmu), length.out = 50)
# Create empty vectors to store means and deviations
vpm <- vpsd <- rep(NA, length(grid))
# Create an empty matrix to store weights
mweights <- matrix(NA, 50, 2)
# Create your for loop
for(i in 1:length(grid)) {
opt <- portfolio.optim(x = returns , pm = grid[i])
vpm[i] <- opt$pm
vpsd[i] <- opt$ps
mweights[i, ] <- opt$pw
}
plot.zoo(vpsd, vpm, type="l", ylim = c(0, max(vpm)))
plot.zoo(vpsd, vpm, type="l")
rf = 0
# Create weights_minvar as the portfolio with the least risk
weights_minvar <- mweights[vpsd == min(vpsd), ]
# Calculate the Sharpe ratio
vsr <- (vpm - rf) / vpsd
# Create weights_max_sr as the portfolio with the maximum Sharpe ratio
weights_max_sr <- mweights[vsr == max(vsr)]
# Create barplot of weights_minvar and weights_max_sr
# par(mfrow = c(2, 1), mar = c(3, 2, 2, 1))
barplot(weights_minvar[weights_minvar > 0.01], main = "Min Variance", ylim = c(0,1))
barplot(weights_max_sr[weights_max_sr > 0.01], main = "Max Sharpe Ratio", ylim = c(0,1))
# Create returns_estim
returns_estim <- window(returns, start = start(returns), end = index(returns[2262,]))
# Create returns_eval
returns_eval <- window(returns, start = index(returns[2263,]), end = end(returns))
# Create vector of max_weights
max_weights <- rep(0.8, ncol(returns))
# Create portfolio with estimation sample
pf_estim <- portfolio.optim(returns_estim, reshigh = max_weights)
# Create portfolio with evaluation sample
pf_eval <- portfolio.optim(returns_eval, reshigh = max_weights)
# Create a scatter plot
plot(pf_estim$pw, pf_eval$pw)
abline(h = 0, b = 1, lty = 3)
# Create returns_pf_estim
returns_pf_estim <- Return.portfolio(returns_estim, pf_estim$pw, rebalance_on = "months")
# Create returns_pf_eval
returns_pf_eval <- Return.portfolio(returns_eval, pf_estim$pw, rebalance_on = "months")
# Print a table for your estimation portfolio
table.AnnualizedReturns(returns_pf_estim)
# Print a table for your evaluation portfolio
table.AnnualizedReturns(returns_pf_eval)
setup algorithm to find next day weights